package com.kc.gb.device.plugins.camera;

import cn.hutool.core.util.StrUtil;
import com.kc.gb.base.dto.Result;
import com.kc.gb.device.common.dto.CameraConfig;
import com.kc.gb.base.dto.DeviceType;
import com.kc.gb.device.common.interfaces.IHardware;
import com.kc.gb.device.common.properties.DeviceProperties;
import com.kc.gb.device.common.utils.SpringHelper;
import com.kc.gb.device.plugins.camera.listener.support.CameraPublishEvent;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service("CAMERA")
public class CameraHardware implements IHardware {

    @Resource
    DeviceProperties deviceProperties;

    @Resource
    ThreadPoolTaskScheduler scheduledThreadPoolExecutor;

    public Map<String, Socket> sockets = new HashMap<>();

    public DeviceType getDeviceType() {
        return DeviceType.CAMERA;
    }

    @Override
    public boolean isEnabled() {
        return deviceProperties.isDeviceCameraEnabled();
    }

    public Result<?> INITIALIZE_RESULT = Result.success();

    @Override
    public Result<?> isConnected() throws Exception {
        return this.INITIALIZE_RESULT;
    }

    @Override
    public boolean testConnect(String ip, int port) throws Exception {
        Socket socket =  new Socket(ip, port);
        boolean result = socket.isConnected();
        socket.close();
        return result;
    }

    public Result<?> initialize() throws Exception {
        List<CameraConfig> connections = deviceProperties.getDeviceCameraConnections();
        boolean allSuccess = true;
        StringBuilder error = new StringBuilder();
        for (CameraConfig config : CollectionUtils.emptyIfNull(connections)) {
            String host = config.getIp();
            int port = config.getPort();
            String point = config.getPoint();
            String station = config.getStation();
            log.info("CameraConfig|ip:{} port:{} point:{} station:{}", host, port, point, station);
            try {
                Socket socket = connectToSocket(host,port,true);
                if(socket.isConnected()){
                    startReadTcpMessage(config,socket);
                }
            } catch (Exception e) {
                allSuccess = false;
                error.append(StrUtil.format("{}:{} {}   ",host,port,e.getClass().getSimpleName()));
            }
        }
        if(allSuccess){
            return Result.success();
        }
        return Result.fail(error.toString());
    }

    @Override
    public void afterInitialize(Result<?> result) throws Exception {
        this.INITIALIZE_RESULT = result;
    }

    public void stopConnect() throws Exception {

    }

    /**
     * 初始化连接
     * @param ip
     * @param port
     * @return
     * @throws IOException
     */
    public Socket connectToSocket(String ip, int port, boolean cacheConnection) throws IOException {
        String key = formatConnectKey(ip,port);
        if(cacheConnection){
            if(!sockets.containsKey(key)){
                Socket socket = new Socket(ip, port);
                sockets.put(key, socket);
            }
            return sockets.get(key);
        }else{
            return new Socket(ip, port);
        }
    }

    /**
     * 读取消息，读取成功调用station接口写入四面码信息
     */
    public void startReadTcpMessage(CameraConfig config, Socket socket) throws Exception {
        Runnable command = new Runnable() {
            @Override
            public void run() {
                try {
                    BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    char[] result = new char[1024];
                    int read = in.read(result);
                    if (read == -1) {
                        // donothing
                    }
                    String response = new String(result, 0, read);
                    SpringHelper.getApplicationContext().publishEvent(new CameraPublishEvent(config,response));
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        };
        scheduledThreadPoolExecutor.scheduleWithFixedDelay(command,0l);
    }

    private String formatConnectKey(String ip,int port){
        return StrUtil.format("{}:{}",ip,port);
    }
}
